/**
 * Copyright 2025 Beijing Volcano Engine Technology Co., Ltd. All Rights Reserved.
 * SPDX-license-identifier: BSD-3-Clause
 */

import { useEffect, useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import VERTC, { MediaType } from '@volcengine/rtc';
import { Modal } from '@arco-design/web-react';
import Utils from '@/utils/utils';
import RtcClient from '@/lib/RtcClient';
import { clearCurrentMsg, localJoinRoom, localLeaveRoom, updateAIGCState, updateLocalUser } from '@/store/slices/room';

import useRtcListeners from '@/lib/listenerHooks';
import { RootState } from '@/store';

import { updateMediaInputs, updateSelectedDevice, setDevicePermissions } from '@/store/slices/device';
import logger from '@/utils/logger';
import aigcConfig, { ScreenShareScene, isVisionMode } from '@/config';
import { generateRtcToken } from '@/services/chatHistory';

export interface FormProps {
  username: string;
  roomId: string;
  publishAudio: boolean;
}

export const useVisionMode = () => {
  const room = useSelector((state: RootState) => state.room);
  return {
    isVisionMode: isVisionMode(room.aiConfig?.Config?.LLMConfig.ModelName),
    isScreenMode: ScreenShareScene.includes(room.scene),
  };
};

export const useDeviceState = () => {
  const dispatch = useDispatch();
  const room = useSelector((state: RootState) => state.room);
  const localUser = room.localUser;
  const isAudioPublished = localUser.publishAudio;
  const isVideoPublished = localUser.publishVideo;
  const isScreenPublished = localUser.publishScreen;
  const queryDevices = async (type: MediaType) => {
    const mediaDevices = await RtcClient.getDevices({
      audio: type === MediaType.AUDIO,
      video: type === MediaType.VIDEO,
    });
    if (type === MediaType.AUDIO) {
      dispatch(
        updateMediaInputs({
          audioInputs: mediaDevices.audioInputs,
        })
      );
      dispatch(
        updateSelectedDevice({
          selectedMicrophone: mediaDevices.audioInputs[0]?.deviceId,
        })
      );
    } else {
      dispatch(
        updateMediaInputs({
          videoInputs: mediaDevices.videoInputs,
        })
      );
      dispatch(
        updateSelectedDevice({
          selectedCamera: mediaDevices.videoInputs[0]?.deviceId,
        })
      );
    }
    return mediaDevices;
  };

  const switchMic = async (controlPublish = true) => {
    if (controlPublish) {
      await (!isAudioPublished ? RtcClient.publishStream(MediaType.AUDIO) : RtcClient.unpublishStream(MediaType.AUDIO));
    }
    queryDevices(MediaType.AUDIO);
    await (!isAudioPublished ? RtcClient.startAudioCapture() : RtcClient.stopAudioCapture());
    dispatch(
      updateLocalUser({
        publishAudio: !isAudioPublished,
      })
    );
  };

  const switchCamera = async (controlPublish = true) => {
    if (controlPublish) {
      await (!isVideoPublished ? RtcClient.publishStream(MediaType.VIDEO) : RtcClient.unpublishStream(MediaType.VIDEO));
    }
    queryDevices(MediaType.VIDEO);
    await (!isVideoPublished ? RtcClient.startVideoCapture() : RtcClient.stopVideoCapture());
    dispatch(
      updateLocalUser({
        publishVideo: !isVideoPublished,
      })
    );
  };

  const switchScreenCapture = async (controlPublish = true) => {
    try {
      if (controlPublish) {
        await (!isScreenPublished ? RtcClient.publishScreenStream(MediaType.VIDEO) : RtcClient.unpublishScreenStream(MediaType.VIDEO));
      }
      await (!isScreenPublished ? RtcClient.startScreenCapture() : RtcClient.stopScreenCapture());
      dispatch(
        updateLocalUser({
          publishScreen: !isScreenPublished,
        })
      );
    } catch {
      console.warn('Not Authorized.');
    }
  };

  return {
    isAudioPublished,
    isVideoPublished,
    isScreenPublished,
    switchMic,
    switchCamera,
    switchScreenCapture,
  };
};

export const useGetDevicePermission = () => {
  const [permission, setPermission] = useState<{
    audio: boolean;
  }>();

  const dispatch = useDispatch();

  useEffect(() => {
    (async () => {
      const permission = await RtcClient.checkPermission();
      dispatch(setDevicePermissions(permission));
      setPermission(permission);
    })();
  }, [dispatch]);
  return permission;
};

export const useJoin = (): [boolean, (formValues: FormProps, fromRefresh: boolean) => Promise<void | boolean>] => {
  const devicePermissions = useSelector((state: RootState) => state.device.devicePermissions);
  const room = useSelector((state: RootState) => state.room);

  const dispatch = useDispatch();

  const { switchCamera, switchMic } = useDeviceState();
  const [joining, setJoining] = useState(false);
  const listeners = useRtcListeners();

  const handleAIGCModeStart = async () => {
    if (room.isAIGCEnable) {
      await RtcClient.stopAudioBot();
      dispatch(clearCurrentMsg());
      await RtcClient.startAudioBot();
    } else {
      await RtcClient.startAudioBot();
    }
    dispatch(updateAIGCState({ isAIGCEnable: true }));
  };

  async function disPatchJoin(formValues: FormProps, fromRefresh: boolean): Promise<void | boolean> {
    if (joining) {
      return;
    }

    const isSupported = await VERTC.isSupported();
    if (!isSupported) {
      Modal.error({
        title: '不支持 RTC',
        content: '您的浏览器可能不支持 RTC 功能，请尝试更换浏览器或升级浏览器后再重试。',
      });
      return;
    }

    setJoining(true);
    const { roomId } = formValues;
    const isVision = isVisionMode(aigcConfig.Model);
    const shouldGetVideoPermission = isVision && !ScreenShareScene.includes(room.scene);

    let token;
    let engineParams;
    let username;
    try {
      // 调用generateRtcToken获取动态token和配置
      const rtcConfig = await generateRtcToken(roomId);
      if (rtcConfig) {
        token = rtcConfig.token;
        username = `${rtcConfig.uid}_${rtcConfig.userName}`;        // 使用服务器返回的配置更新引擎参数
        engineParams = {
          appId: rtcConfig.appId,
          roomId: rtcConfig.roomId,
          uid: username, // 仍然使用表单中的用户名作为uid
        };
      } else {
        // 抛出异常，禁止加入
        throw new Error('获取RTC Token失败: 服务器返回数据为空');
      }
    } catch (error) {
      console.error('获取RTC Token失败:', error);
      // 显示错误提示
      Modal.error({
        title: 'RTC Token错误',
        content: `无法获取RTC Token，禁止加入房间: ${error instanceof Error ? error.message : String(error)}`,
      });
      setJoining(false);
      return false;
    }

    try {
      // 1. Create RTC Engine
      await RtcClient.createEngine(engineParams);

      // 更新 RtcClient.basicInfo 中的 token
      RtcClient.basicInfo.login_token = token;

      // 2.1 Set events callbacks
      RtcClient.addEventListeners(listeners);

      // 2.2 RTC starting to join room
      await RtcClient.joinRoom(token, username);
      console.log(' ------ userJoinRoom\n', `roomId: ${roomId}\n`, `uid: ${username}`);

      // 3. Set users' devices info
      const mediaDevices = await RtcClient.getDevices({
        audio: true,
        video: shouldGetVideoPermission,
      });

      dispatch(
        localJoinRoom({
          roomId,
          user: {
            username,
            userId: username,
          },
        })
      );
      dispatch(
        updateSelectedDevice({
          selectedMicrophone: mediaDevices.audioInputs[0]?.deviceId,
          selectedCamera: mediaDevices.videoInputs[0]?.deviceId,
        })
      );
      dispatch(updateMediaInputs(mediaDevices));

      if (devicePermissions.audio) {
        try {
          await switchMic();
          // RtcClient.setAudioVolume(30);
        } catch (e) {
          logger.debug('No permission for mic');
        }
      }

      if (devicePermissions.video && shouldGetVideoPermission) {
        try {
          await switchCamera();
        } catch (e) {
          logger.debug('No permission for camera');
        }
      }

      Utils.setSessionInfo({
        username,
        roomId,
        publishAudio: true,
      });

      handleAIGCModeStart();

      return true;
    } catch (error: any) {
      console.error('RTC 加入房间失败:', error);

      // 显示错误提示
      if (error.toString().includes('token_error')) {
        Modal.error({
          title: 'RTC Token 错误',
          content: 'RTC Token 无效或已过期。请更新配置文件中的 Token 后重试。您可以在火山引擎控制台生成临时Token。',
        });
      } else {
        Modal.error({
          title: 'RTC 加入房间失败',
          content: `发生错误: ${error.message || error}`,
        });
      }

      return false;
    } finally {
      setJoining(false);
    }
  }

  return [joining, disPatchJoin];
};

export const useLeave = () => {
  const dispatch = useDispatch();

  return async function () {
    try {
      // 尝试停止所有捕获
      try {
        // 首先检查engine是否存在
        if (RtcClient.engine) {
          await Promise.all([
            RtcClient.stopAudioCapture(),
            RtcClient.stopScreenCapture(),
            RtcClient.stopVideoCapture()
          ]);
        } else {
          logger.warn('RTC引擎未初始化，跳过捕获停止步骤');
        }
      } catch (captureError) {
        logger.error('停止捕获失败:', captureError);
        // 继续执行，不让捕获错误阻止离开房间
      }

      // 尝试离开房间
      try {
        await RtcClient.leaveRoom();
      } catch (leaveError) {
        logger.error('离开房间失败:', leaveError);
        // 继续执行，确保UI状态更新
      }

      // 无论如何都更新Redux状态
      dispatch(localLeaveRoom());
      dispatch(updateAIGCState({ isAIGCEnable: false }));
    } catch (error) {
      logger.error('离开房间过程中发生错误:', error);
      // 确保UI状态更新
      dispatch(localLeaveRoom());
      dispatch(updateAIGCState({ isAIGCEnable: false }));
    }
  };
};
